from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
import numpy as np
import pandas as pd
from tensorflow import keras
from keras.models import Sequential
from keras.layers import LSTM, Dense,Flatten
from keras.callbacks import EarlyStopping
from sklearn.preprocessing import MinMaxScaler
from django.db.models import CharField
from dataset.models import DatasetInfo
from django.db.models.functions import Cast
from django.conf import settings
from datetime import datetime, timedelta
import os


# Create predict views here.


class AQIPredictionLSTM(View):

    def get(self, request):
        # 获取用户名
        username = request.COOKIES.get('user_name')

        # os.listdir  media/datasets文件夹下的所有文件名
        datasets_path = os.path.join(settings.MEDIA_ROOT, 'datasets')
        datasets = os.listdir(datasets_path)
        # 获取当前日期（只保留年月日）
        today = datetime.now().date()
        # 计算明天的日期（只保留年月日）
        tomorrow = today + timedelta(days=1)
        # 计算未来15天的日期（只保留年月日），并转换为指定格式的字符串，放在一个列表里面
        future_dates = [((tomorrow + timedelta(days=i)).strftime('%Y-%m-%d')) for i in range(15)]
        # 准备传入模板的上下文数据
        context = {
            'username': username,
            'provinces': [province.replace('.csv', '') for province in datasets],
            'future_dates': future_dates,
            'index_list': list(range(15)),
        }
        return render(request, 'predict/AQI-prediction.html', context=context)

    def post(self, request):
        # 获取用户想要预测的省份
        province = request.POST.get('province')
        data_path = os.path.join(settings.MEDIA_ROOT, f'datasets\\{province}.csv')
        data = pd.read_csv(data_path)
        # data
        # 选择前10列
        first_ten_data = data.iloc[:, 2:10]
        first_ten_data['time'] = pd.to_datetime(first_ten_data['time'])
        first_ten_data = first_ten_data.set_index('time')

        # 数据预处理
        scaler = MinMaxScaler(feature_range=(0, 1))
        scaled_aqi = scaler.fit_transform(first_ten_data['aqi'].values.reshape(-1, 1))
        # 用过去的700天数据来预测接下来的n天（n指明天是这一年中的第几天）
        # 获取当前日期
        today = datetime.now()
        # 计算明天的日期
        tomorrow = today + timedelta(days=1)
        # 使用 .timetuple().tm_yday 获取一年中的第几天
        day_of_year_tomorrow = tomorrow.timetuple().tm_yday
        print(f"明天（{tomorrow.strftime('%Y-%m-%d')}）是一年中的第 {day_of_year_tomorrow} 天。")
        past_history = 700
        future_target = day_of_year_tomorrow + 14  # 预测未来15天的AQI
        X_train, y_train = create_dataset(scaled_aqi, 0, None, past_history, future_target)
        y_train = y_train.reshape(y_train.shape[0], y_train.shape[1])

        # 创建MLP模型
        model = Sequential()
        model.add(Flatten())
        model.add(Dense(512))
        model.add(Dense(128))
        model.add(Dense(future_target))
        model.compile(optimizer='adam', loss='mse')
        # 训练模型
        early_stop = EarlyStopping(monitor='loss', patience=10)
        history = model.fit(X_train, y_train, epochs=100, batch_size=32, callbacks=[early_stop], verbose=1)
        # 进行预测
        prediction = model.predict(X_train[-1].reshape(1, past_history, 1))
        # 逆缩放预测结果
        predicted_aqi = scaler.inverse_transform(prediction).flatten()

        # 创建预测日期的范围
        last_date = first_ten_data.index[-1]
        # predicted_dates = pd.date_range(start=last_date, periods=future_target+1, closed='right')
        predicted_dates = pd.date_range(start=last_date, periods=future_target + 1)[1:]

        # 创建包含预测结果的DataFrame
        predicted_df = pd.DataFrame({
            '日期': predicted_dates,
            '预测aqi': predicted_aqi
        })

        result_value = predicted_df.iloc[-1, 1]  # 获取一天的预测结果
        result_value_15 = predicted_df.iloc[-15:, 1]  # 获取15天的预测结果

        print(predicted_df.iloc[-15:, 0].apply(lambda x: x.strftime('%Y-%m-%d')).tolist())
        print(predicted_df.iloc[-15:, 1].tolist())
        print([calculate_aqi_level(int(x)) for x in predicted_df.iloc[-15:, 1].tolist()])

        return JsonResponse({
            'predicted_data_list': predicted_df.iloc[-15:, 0].apply(lambda x: x.strftime('%Y-%m-%d')).tolist(),
            'predicted_aqi_list': predicted_df.iloc[-15:, 1].tolist(),
            'suggestion_list': [calculate_aqi_level(int(x)) for x in predicted_df.iloc[-15:, 1].tolist()]
        })


class AQIPredictionGRU(View):

    def get(self, request):
        # 获取用户名
        username = request.COOKIES.get('user_name')

        # os.listdir  media/datasets文件夹下的所有文件名
        datasets_path = os.path.join(settings.MEDIA_ROOT, 'datasets')
        datasets = os.listdir(datasets_path)

        # 准备传入模板的上下文数据
        context = {
            'username': username,
            'provinces': [province.replace('.csv', '') for province in datasets],
        }
        return render(request, 'predict/AQI-prediction-gru.html', context=context)







# 创建LSTM需要的序列数据
def create_dataset(dataset, start_index, end_index, history_size, target_size):
    """
    根据给定的参数从数据集中提取序列数据及其对应的标签。

    参数:
    dataset: 一维数组，包含所有数据点。
    start_index: 数据提取的起始索引。
    end_index: 数据提取的结束索引，可以为None，默认提取到数据集末尾。
    history_size: 序列的历史长度，即输入序列的长度。
    target_size: 序列的目标长度，即输出序列的长度。

    返回:
    一个包含数据和标签的元组。数据是一个三维数组，标签是一个二维数组。
    """
    # 初始化存储数据和标签的列表
    data = [];
    labels = []

    # 调整起始索引，确保它位于历史长度之后
    start_index = start_index + history_size
    # 如果未指定结束索引，则将其设置为数据集末尾减去目标长度
    if end_index is None:
        end_index = len(dataset) - target_size

    # 遍历数据集，从起始索引到结束索引
    for i in range(start_index, end_index):
        # 构建当前索引处的历史数据序列
        indices = range(i - history_size, i)
        # 将历史数据序列reshape为LSTM所需的格式
        data.append(np.reshape(dataset[indices], (history_size, 1)))
        # 添加当前索引处的标签
        labels.append(dataset[i:i + target_size])
    # 将数据和标签转换为numpy数组并返回
    return np.array(data), np.array(labels)



# 计算AQI等级
def calculate_aqi_level(aqi):
    if aqi <= 50:
        return '<p>空气质量：优</p><p>健康影响：空气质量令人满意，基本无空气污染</p><p>建议措施：各类人群可正常活动</p>'
    elif aqi <= 100:
        return '<p>空气质量：良</p><p>健康影响：空气质量可接受，但某些污染物可能对极少数异常敏感人群健康有较弱影响</p><p>建议措施：极少数异常敏感人群应减少户外活动</p>'
    elif aqi <= 150:
        return '<p>空气质量：轻度污染</p><p>健康影响：易感人群症状有轻度加剧，健康人群出现刺激症状</p><p>建议措施：儿童、老年人及心脏病、呼吸系统疾病患者应减少长时间、高强度的户外锻炼</p>'
    elif aqi <= 200:
        return '<p>空气质量：中度污染</p><p>健康影响：进一步加剧易感人群症状，可能对健康人群心脏、呼吸系统有影响</p><p>建议措施：儿童、老年人及心脏病、呼吸系统疾病患者避免长时间、高强度的户外锻练，一般人群适是减少户外运动</p>'
    elif aqi <= 300:
        return '<p>空气质量：重度污染</p><p>健康影响：心脏病和肺病患者症状显著加剧，运动耐受力降低，健康人群普遍出现症状</p><p>建议措施：儿童、老年人和心脏病、肺病患者应停留在室内，停止户外运动，一般人群减少户外运动</p>'
    else:
        return '<p>空气质量：严重污染</p><p>健康影响：健康人群运动耐受力降低，有明显强烈症状，提前出现某些疾病</p><p>建议措施：儿童、老年人和病人应当留在室内避免体力消耗，一般人群应避免户外活动</p>'
